//
//  DevicesModel.m
//  Shion
//
//  Created by Chris Karr on 12/17/07.
//  Copyright 2007-2008 Audacious Software. All rights reserved.
//

#import "DevicesModel.h"
#import "Device.h"
#import "DeviceStatus.h"
#import "DeviceManager.h"
#import "ShionAppDelegate.h"

#define DEVICE_MODEL_UPDATE  @"Shion: Device Model: Model Update"
#define USE_FIXED_INTERVAL @"Fixed-Interval"
#define INITAL_INTERVAL 5.0
#define INTERVAL_COUNT_WINDOW 4
#define MAX_INTERVAL 300.0

@implementation DevicesModel

@synthesize timer;

- (void) broadcastStatus:(NSNotification *) notification
{
	NSMutableArray * array = [NSMutableArray array];
	
	for (Device * device in [devices arrangedObjects])
	{
		NSMutableDictionary * dict = [NSMutableDictionary dictionary];
		
		[dict setValue:device.actualStatus.lightLevel forKey:@"level"];
		[dict setValue:device.address forKey:@"address"];
		[dict setValue:device.name forKey:@"name"];
		
		[array addObject:dict];
	}

	NSMutableDictionary * userInfo = [NSMutableDictionary dictionary];
	[userInfo setValue:array forKey:@"devices"];
	
	[[NSNotificationCenter defaultCenter] postNotificationName:DEVICE_STATUS_BROADCAST object:self userInfo:userInfo];
}

- (void) awakeFromNib
{
	self.timer = [NSTimer scheduledTimerWithTimeInterval:INITAL_INTERVAL 
												  target:self
												selector:@selector(synchronize:) 
												userInfo:nil 
												 repeats:NO];
}

- (void) synchronize:(NSTimer *) theTimer
{
	for (Device * device in [devices arrangedObjects])
	{
		if (device.todoStatus.lightLevel != nil && device.actualStatus.lightLevel != nil)
		{
			NSInteger actual = [device.actualStatus.lightLevel integerValue];
			NSInteger todo = [device.todoStatus.lightLevel integerValue];

			if (todo != actual)
			{
				NSMutableDictionary * dict = [NSMutableDictionary dictionary];
				[dict setValue:device.address forKey:@"address"];
			
				[dict setValue:@"set" forKey:@"action"];
				[dict setValue:[NSNumber numberWithInt:todo] forKey:@"level"];
				
				[[NSNotificationCenter defaultCenter] postNotificationName:SHION_INSTRUCTION 
																	object:dict 
																  userInfo:nil];
			}
			else
				[device pingStatus];
		}
		else
			[device pingStatus];
	}
	
	updateCount += 1;

	if (self.timer == nil)
		updateCount = 0;
	else
	{
		[self.timer invalidate];
		self.timer = nil;
	}
	
	CGFloat interval = INITAL_INTERVAL + (5 * updateCount * [[devices arrangedObjects] count]);

	NSNumber * fixed = [[NSUserDefaults standardUserDefaults] objectForKey:USE_FIXED_INTERVAL];

	if (fixed != nil)
	{
		if ([fixed boolValue])
			interval = INITAL_INTERVAL;
	}
	
	if (interval > 300)
		interval = 300;
	
	self.timer = [NSTimer scheduledTimerWithTimeInterval:((double) interval)
												  target:self
												selector:@selector(synchronize:) 
												userInfo:nil 
												 repeats:NO];
}

- (void) updateStatus:(NSNotification *) notification
{
	NSDictionary * dict = [notification userInfo];
	NSData * address = [dict valueForKey:@"Device"];
	
	for (Device * device in [devices arrangedObjects])
	{
		if ([address isEqual:device.address])
		{
			DeviceStatus * status = device.actualStatus;
			DeviceStatus * todo = device.todoStatus;
			NSNumber * level = [dict valueForKey:@"Value"];

			NSDate * now = [NSDate date];
			
			if (status.lightLevel == nil || [level integerValue] != [status.lightLevel integerValue])
			{
				todo.lightLevel = nil;
				todo.lastUpdate = now;

				status.lightLevel = level;
				status.lastUpdate = now;

				[[NSNotificationCenter defaultCenter] postNotificationName:DEVICES_UPDATED 
																	object:[NSNumber numberWithBool:YES] 
																  userInfo:nil];
			}
		}
	}
}

- (void) sync:(NSNotification *) theNote
{
	[self synchronize:nil];
}

- (DevicesModel *) init
{
	if (self = [super init])
	{
		updateCount = 0;
		
		NSNotificationCenter * defaultCenter = [NSNotificationCenter defaultCenter];
		
		[defaultCenter addObserver:self selector:@selector(updateStatus:) name:DEVICE_STATUS_UPDATE object:nil];
		[defaultCenter addObserver:self selector:@selector(broadcastStatus:) name:DEVICE_STATUS_REQUEST object:nil];
		[defaultCenter addObserver:self selector:@selector(sync:) name:SHION_SYNCNOW object:nil];
	}
	
	return self;
}

@end
